#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <errno.h>
#include <termios.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdbool.h>
#include <mosquitto.h>

#define COM "/dev/ttyUSB0"
#define SENSOR_ADDR 0x14      // 修改为0x14（原0x1A）
#define RELAY_ADDR 0x29
#define MODBUS_READ_CODE 0x03
#define MODBUS_WRITE_CODE 0x06
#define MODBUS_REQ_LEN 8
#define MODBUS_REQ_INTERVAL 3

// MQTT配置
#define BROKER_HOST "localhost"
#define BROKER_PORT 1883
#define PUB_TOPIC "cdjc/sensor"
#define SUB_TOPIC "cdjc/control"
#define MQTT_QOS 1
#define KEEPALIVE 60

// 继电器寄存器地址
#define RELAY_START_ADDR 0x000E
#define ALL_RELAYS_ON 0xAAAA
#define ALL_RELAYS_OFF 0xBBBB

typedef struct __attribute__((packed)) {
    float x_value;
    float y_value;
    float z_value;
    float t_ds18b20;
    int16_t t_dht11;
    uint16_t humidity;
} modbus_sensor_t;

// 全局变量
struct mosquitto *mosq = NULL;
pthread_mutex_t mqtt_mutex = PTHREAD_MUTEX_INITIALIZER;
int fd;
pthread_t tid_tx, tid_rx;
volatile sig_atomic_t running = 1;

// Modbus CRC16计算
uint16_t modbus_crc16(const uint8_t *data, uint16_t length) {
    uint16_t crc = 0xFFFF;
    
    for (uint16_t i = 0; i < length; i++) {
        crc ^= data[i];
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    
    return crc;
}

// CRC16计算（包装函数）
void crc16(uint8_t *data, uint8_t len, uint8_t *crc_lb, uint8_t *crc_hb) {
    uint16_t crc = modbus_crc16(data, len);
    *crc_lb = crc & 0xFF;
    *crc_hb = (crc >> 8) & 0xFF;
}

// 验证Modbus帧CRC
bool verify_modbus_crc(const uint8_t *data, uint16_t length) {
    if (length < 2) return false;
    
    uint16_t received_crc = (data[length - 1] << 8) | data[length - 2];
    uint16_t calculated_crc = modbus_crc16(data, length - 2);
    
    return (received_crc == calculated_crc);
}

// 生成继电器控制帧
void build_relay_control_frame(uint8_t *frame, uint16_t relay_num, uint16_t value) {
    frame[0] = RELAY_ADDR;
    frame[1] = MODBUS_WRITE_CODE;
    frame[2] = (RELAY_START_ADDR + relay_num - 1) >> 8;
    frame[3] = (RELAY_START_ADDR + relay_num - 1) & 0xFF;
    frame[4] = value >> 8;
    frame[5] = value & 0xFF;
    crc16(frame, 6, &frame[6], &frame[7]);
}

// 发送Modbus控制命令
void send_control_command(int relay_num, bool state) {
    uint8_t control_frame[MODBUS_REQ_LEN];
    
    if (relay_num == 0) {
        build_relay_control_frame(control_frame, 1, state ? ALL_RELAYS_ON : ALL_RELAYS_OFF);
        printf("控制所有继电器: %s\n", state ? "ON" : "OFF");
    } else {
        build_relay_control_frame(control_frame, relay_num, state ? 0x0001 : 0x0000);
        printf("控制继电器%d: %s\n", relay_num, state ? "ON" : "OFF");
    }

    printf("发送Modbus帧: ");
    for (int i = 0; i < MODBUS_REQ_LEN; i++) {
        printf("%02X ", control_frame[i]);
    }
    printf("\n");

    pthread_mutex_lock(&mqtt_mutex);
    write(fd, control_frame, MODBUS_REQ_LEN);
    pthread_mutex_unlock(&mqtt_mutex);
}

// MQTT消息回调
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) {
    if (msg->payloadlen > 0 && strcmp(msg->topic, SUB_TOPIC) == 0) {
        char *payload = (char *)msg->payload;
        printf("收到控制命令: %s\n", payload);

        int relay_num, state;
        if (sscanf(payload, "%d,%d", &relay_num, &state) == 2) {
            if ((relay_num >= 0 && relay_num <= 4) && (state == 0 || state == 1)) {
                send_control_command(relay_num, (bool)state);
            } else {
                fprintf(stderr, "无效命令: 继电器=%d 状态=%d\n", relay_num, state);
            }
        } else {
            fprintf(stderr, "命令格式错误! 应为'继电器,状态'\n");
        }
    }
}

// 初始化MQTT
int init_mqtt() {
    mosquitto_lib_init();
    char client_id[24];
    snprintf(client_id, sizeof(client_id), "gateway_%d", getpid());
    
    mosq = mosquitto_new(client_id, true, NULL);
    if (!mosq) {
        fprintf(stderr, "MQTT初始化失败\n");
        return -1;
    }

    mosquitto_threaded_set(mosq, true);
    mosquitto_message_callback_set(mosq, on_message);

    if (mosquitto_connect(mosq, BROKER_HOST, BROKER_PORT, KEEPALIVE) != MOSQ_ERR_SUCCESS) {
        fprintf(stderr, "无法连接MQTT代理\n");
        return -1;
    }

    if (mosquitto_subscribe(mosq, NULL, SUB_TOPIC, MQTT_QOS) != MOSQ_ERR_SUCCESS) {
        fprintf(stderr, "订阅主题失败\n");
        return -1;
    }

    printf("已连接MQTT并订阅主题: %s\n", SUB_TOPIC);
    return 0;
}

// 字节序转换
void byte_order_reverse(uint8_t *data, size_t length) {
    for (size_t i = 0; i < length / 2; i++) {
        uint8_t temp = data[i];
        data[i] = data[length - 1 - i];
        data[length - 1 - i] = temp;
    }
}

/*========== 修改点2：传感器数据解析中的地址校验 ==========*/
void parse_sensor_data(uint8_t *data) {
    // 地址校验（必须为0x14）
    if (data[0] != SENSOR_ADDR) {
        fprintf(stderr, "无效设备地址: 0x%02X (应为0x14)\n", data[0]);
        return;
    }

    modbus_sensor_t sensor;
    memcpy(&sensor, data + 3, sizeof(modbus_sensor_t));
    
    byte_order_reverse((uint8_t*)&sensor.x_value, sizeof(sensor.x_value));
    byte_order_reverse((uint8_t*)&sensor.y_value, sizeof(sensor.y_value));
    byte_order_reverse((uint8_t*)&sensor.z_value, sizeof(sensor.z_value));
    byte_order_reverse((uint8_t*)&sensor.t_ds18b20, sizeof(sensor.t_ds18b20));
    byte_order_reverse((uint8_t*)&sensor.t_dht11, sizeof(sensor.t_dht11));
    byte_order_reverse((uint8_t*)&sensor.humidity, sizeof(sensor.humidity));

    printf("传感器数据: x=%.2f, y=%.2f, z=%.2f, t1=%.2f, t2=%d, h=%d\n",
           sensor.x_value, sensor.y_value, sensor.z_value,
           sensor.t_ds18b20, sensor.t_dht11, sensor.humidity);

    // 发布到MQTT
    char payload[256];
    snprintf(payload, sizeof(payload),
             "{\"x\":%.2f,\"y\":%.2f,\"z\":%.2f,\"t1\":%.2f,\"t2\":%d,\"h\":%d}",
             sensor.x_value, sensor.y_value, sensor.z_value,
             sensor.t_ds18b20, sensor.t_dht11, sensor.humidity);

    pthread_mutex_lock(&mqtt_mutex);
    mosquitto_publish(mosq, NULL, PUB_TOPIC, strlen(payload), payload, MQTT_QOS, false);
    pthread_mutex_unlock(&mqtt_mutex);
}

/*========== 修改点3：查询线程中的设备地址 ==========*/
void *com_tx_thread(void *arg) {
    uint8_t request[MODBUS_REQ_LEN] = {
        SENSOR_ADDR,  // 使用新地址0x14
        MODBUS_READ_CODE,
        0x00, 0x04, 0x00, 0x0A, 0x00, 0x00  // CRC将由crc16函数填充
    };
    
    // 计算并填充CRC
    crc16(request, 6, &request[6], &request[7]);

    while (running) {
        pthread_mutex_lock(&mqtt_mutex);
        write(fd, request, MODBUS_REQ_LEN);
        pthread_mutex_unlock(&mqtt_mutex);
        sleep(MODBUS_REQ_INTERVAL);
    }
    return NULL;
}

// 接收线程
void *com_rx_thread(void *arg) {
    uint8_t rx_buf[256];
    int len;

    while (running) {
        len = read(fd, rx_buf, sizeof(rx_buf));
        if (len >= 25) {  // 传感器数据帧长度
            if (!verify_modbus_crc(rx_buf, len)) {
                fprintf(stderr, "CRC校验失败，丢弃数据帧\n");
                continue;
            }
            parse_sensor_data(rx_buf);
        } else if (len > 0) {
            printf("收到非传感器数据帧(%d字节): ", len);
            for (int i = 0; i < len; i++) {
                printf("%02X ", rx_buf[i]);
            }
            
            if (!verify_modbus_crc(rx_buf, len)) {
                printf("[CRC校验失败]");
            } else {
                printf("[CRC校验成功]");
            }
            printf("\n");
        }
    }
    return NULL;
}

// 清理资源
void cleanup() {
    running = 0;
    if (mosq) {
        mosquitto_disconnect(mosq);
        mosquitto_destroy(mosq);
    }
    mosquitto_lib_cleanup();
    if (fd > 0) close(fd);
}

// 信号处理
void on_sigint(int sig) {
    cleanup();
    printf("\n网关已停止\n");
    exit(0);
}

// 主函数
int main(int argc, char *argv[]) {
    signal(SIGINT, on_sigint);
    atexit(cleanup);

    // 初始化MQTT
    if (init_mqtt() != 0) {
        return 1;
    }

    // 打开串口
    const char *com = (argc == 1) ? COM : argv[1];
    fd = open(com, O_RDWR | O_NOCTTY);
    if (fd == -1) {
        perror("串口打开失败");
        return 1;
    }

    // 配置串口
    struct termios newtio;
    memset(&newtio, 0, sizeof(newtio));
    newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
    newtio.c_iflag = 0;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;
    newtio.c_cc[VMIN] = 0;
    newtio.c_cc[VTIME] = 10;
    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &newtio);

    printf("已打开串口: %s (115200 bps)\n", com);

    // 创建线程
    pthread_create(&tid_tx, NULL, com_tx_thread, NULL);
    pthread_create(&tid_rx, NULL, com_rx_thread, NULL);

    // MQTT事件循环
    while (running) {
        int rc = mosquitto_loop(mosq, 1000, 1);
        if (rc != MOSQ_ERR_SUCCESS && running) {
            fprintf(stderr, "MQTT连接错误，尝试重连...\n");
            sleep(1);
            mosquitto_reconnect(mosq);
        }
    }

    pthread_join(tid_tx, NULL);
    pthread_join(tid_rx, NULL);
    return 0;
}
